
#include <xbi/xbidmi.h>

#if 0
#pragma mark Definitions
#endif

static char * _XBIXboxString = "XBOX";
#define _XBIXboxStringLength 4

struct _XBIDiskManufacturingInformation {
    byte_t * data;
    int size;
    
    time_t masteringDate;
    byte_t mediaID[_XBIDMIMediaIDLength];
};

#if 0
#pragma mark Creation - Copy - Deletion
#endif

XBIDiskManufacturingInformation * XBIDMICreateFromBuffer(byte_t * buffer, int size, XBIError * error) {
    XBIDiskManufacturingInformation * newDMI = NULL;
    
    if (XBIBufferIsEmpty(buffer, size)) {
        XBILog("Disk manufacturing information sector buffer is empty, ignoring\n");
        *error = kXBIFileWrongFormat;
        goto error;
    }
    
    XBILog("Checking DMI buffer for integrity\n");
    
    if (size != _XBIDiskManufacturingInformationSize) {
        XBILog("Disk manufacturing information buffer doesn't have the right size\n");
        *error = kXBIFileWrongFormat;
        goto error;
    }
    
    XBILog("DMI buffer has correct length\n");
    
    newDMI = malloc(sizeof(XBIDiskManufacturingInformation));    
    if (newDMI == NULL) {
        *error = kXBINotEnoughMemory;
        goto error;
    }
    memset(newDMI, 0, sizeof(XBIDiskManufacturingInformation));
    
    newDMI->size = size;

    newDMI->data = malloc(_XBIDiskManufacturingInformationSize);
    if (newDMI->data == NULL) {
        *error = kXBINotEnoughMemory;
        goto error;
    }

    memcpy(newDMI->data, buffer, _XBIDiskManufacturingInformationSize);
    
    XBILog("Checking for presence of 'XBOX' string in DMI\n");
    // checking for xbox works for 360 dmis, but not xbox 1
    if (memcmp(newDMI->data + 2024, _XBIXboxString, _XBIXboxStringLength) == 0) {
        XBILog("XBOX string found\n");
    } else {
        XBILog("XBOX string NOT found in DMI\n");
        goto error;
    }
    
    newDMI->masteringDate = XBIWin32FileTimeToUnixTime(XBIReadLittleEndianInt64AtAddress(newDMI->data + 0x10));

    XBILog("Mastering date : %s", ctime(&newDMI->masteringDate));
    
    memcpy(newDMI->mediaID, newDMI->data + 0x20, _XBIDMIMediaIDLength);
    XBILog("MediaID : %s\n", newDMI->mediaID);

    
    return newDMI;
error:
    XBIDMIDelete(newDMI);    
    return NULL;
}

XBIDiskManufacturingInformation * XBIDMICreateFromFile(FILE * file, XBIError * error) {
    size_t bufferSize = 0;
    byte_t * buffer = XBICreateBufferFromFile(file, &bufferSize);
    return XBIDMICreateFromBuffer(buffer, bufferSize, error);
}

XBIDiskManufacturingInformation * XBIDMICopy(XBIDiskManufacturingInformation * dmi) {
    // TODO: Real copy
    return dmi;
}

void XBIDMIDelete(XBIDiskManufacturingInformation * dmi) {
    if (dmi != NULL) {
        if (dmi->data != NULL) {
            free(dmi->data);
            dmi->data = NULL;
        }        
        free(dmi);
    }
}

#if 0
#pragma mark Data manipulation
#endif

uint32_t XBIDMIGetCRC32(XBIDiskManufacturingInformation * dmi) {
    if (dmi == NULL || dmi->data == NULL || dmi->size == 0)
        return 0;
    return XBIComputeCRC32(dmi->data, dmi->size);
}

#if 0
#pragma mark Accessors
#endif

time_t XBIDMIGetMasteringDate(XBIDiskManufacturingInformation * dmi) {
    if (dmi != NULL)
        return dmi->masteringDate;
    return -1;
}

byte_t * XBIDMIGetMediaID(XBIDiskManufacturingInformation * dmi) {
    if (dmi != NULL)
        return dmi->mediaID;
    return NULL;
}

byte_t * XBIDMIGetData(XBIDiskManufacturingInformation * dmi) {
    if (dmi != NULL)
        return dmi->data;
    return NULL;
}

size_t XBIDMIGetSize(XBIDiskManufacturingInformation * dmi) {
    if (dmi != NULL)
        return dmi->size;
    return -1;
}

